package com.example.zhongshuishi.utils;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.example.zhongshuishi.DemoConfig;
import io.micrometer.common.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/*
 * ourpay工具类
 */
public class OurpayKit {

    // 修改: 将 AES_KEY 定义为静态常量，确保初始化正确
    private static final byte[] AES_KEY = "cUbPFYFNVG}*3}5[m3|K9kfL".getBytes();

    /** 加密 **/
    public static String aesEncode(String str) {
        return SecureUtil.aes(AES_KEY).encryptHex(str);
    }

    public static String aesDecode(String str) {
        return SecureUtil.aes(AES_KEY).decryptStr(str);
    }

    // 修改: 将 encodingCharset 定义为静态常量
    private static final String encodingCharset = "UTF-8";

    public static String getSign(Map<String, Object> map) {
        String sign = "";
        if ("MD5".equals(DemoConfig.signType)) {
            sign = OurpayKit.unionSign(map, DemoConfig.md5Key, "MD5");
        }
//        else if ("SM2".equals(DemoConfig.signType)) {
//            sign = OurpayKit.unionSign(map, DemoConfig.priSm2Key, "SM2");
//        }
        else if ("RSA".equals(DemoConfig.signType)) {
            sign = OurpayKit.unionSign(map, DemoConfig.priRsaKey, "RSA");
        }
        return sign;
    }

    public static Boolean checkSign(String ret) {
        Boolean flag = false;
        if(StringUtils.isEmpty(ret)){
            System.out.println("返回为空，不验签");
            return false;
        }
        JSONObject jsonObject = JSONObject.parseObject(ret);
        if(!"0".equals(jsonObject.getString("code"))){
            System.out.println("返回失败，不验签");
            return false;
        }
        JSONObject data = jsonObject.getJSONObject("data");
        data.put("sign", jsonObject.getString("sign"));
        if ("MD5".equals(DemoConfig.signType)) {
            flag = OurpayKit.validSign((Map<String, Object>) data, DemoConfig.md5Key, "MD5",null);
        }
//        else if ("SM2".equals(DemoConfig.signType)) {
//            flag = OurpayKit.validSign(data, DemoConfig.pubSm2Key, "SM2","Allinpay");
//        }
        else if ("RSA".equals(DemoConfig.signType)) {
            flag = OurpayKit.validSign(data, DemoConfig.priRsaKey, "RSA",null);
        }
        return flag;
    }

    public static String unionSign(Map<String, Object> params, String appkey, String signType) {
        if (org.apache.commons.lang3.StringUtils.isBlank(signType)) {
            signType = "MD5";
        }
        //Map<String, Object> sortedMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        Map<String, Object> sortedMap = new TreeMap<>();//区分大小写
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            if (!"sign".equals(entry.getKey())) {
                sortedMap.put(entry.getKey(), entry.getValue());
            }
        }
        // params.remove("sign");
//		if (CS.SIGN_TYPE.MD5.equals(signType)) {// 如果是md5则需要把md5的key加入到排序
//			sortedMap.put("key", appkey);
//		}
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
            String value = String.valueOf(entry.getValue());
            if (entry.getValue() != null && value.length() > 0) {
                sb.append(entry.getKey()).append("=").append(value).append("&");
            }
        }
        if ("MD5".equals(signType)) {
            sb.append("key=").append(appkey).append("&");
        }
        if (sb.length() > 0 && "&".equals(String.valueOf(sb.charAt(sb.length() - 1)))) {
            sb.deleteCharAt(sb.length() - 1);
        }
        System.out.println(sb.toString());
        String sign = "";
        System.out.println(sb.toString());
        try {
            if ("MD5".equals(signType)) {
                sign = md5(sb.toString(), encodingCharset).toUpperCase();// 记得是md5编码的加签
                // params.remove("key");
            }
//            else if ("SM2".equals(signType)) {
//                PrivateKey privkey = SmUtils.privKeySM2FromBase64Str(appkey);
//                sign = SmUtils.signSM3SM2RetBase64(privkey, String.valueOf(params.get("appId")),
//                        sb.toString().getBytes(encodingCharset));// 签名
//            }
            else if ("RSA".equals(signType)) {
                sign = RsaUtils.rsaSign(sb.toString(), appkey, encodingCharset);
            } else {
                System.out.println("sign type error :" + signType);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sign;
    }

    public static boolean validSign(Map<String, Object> param, String appkey, String signType, String certId) {
        if (param != null && !param.isEmpty()) {
            if (!param.containsKey("sign"))
                return false;
            String sign = param.get("sign").toString();
            if (StringUtils.isBlank(signType)) {
                signType = "MD5";
            }
            Map<String, Object> sortedMap = new TreeMap<>(); // 区分大小写
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                if (!"sign".equals(entry.getKey())) {
                    sortedMap.put(entry.getKey(), entry.getValue());
                }
            }
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
                if (entry.getValue() != null && entry.getValue().toString().length() > 0) {
                    sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
                }
            }
            if ("MD5".equals(signType)) {
                sb.append("key=").append(appkey);
            }
            if (sb.length() > 0 && "&".equals(String.valueOf(sb.charAt(sb.length() - 1)))) {
                sb.deleteCharAt(sb.length() - 1);
            }
            try {
                if ("MD5".equals(signType)) {
                    return sign.toLowerCase().equals(md5(sb.toString(), encodingCharset).toLowerCase());
                } else if ("SM2".equals(signType)) {
                    System.out.println("SM2 验签逻辑暂未实现");
                } else if ("RSA".equals(signType)) {
                    System.out.println("RSA 验签逻辑暂未实现");
                } else {
                    System.out.println("sign type error :{}" + signType);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public static String md5(String value, String charset) {
        MessageDigest md = null;
        try {
            byte[] data = value.getBytes(charset);
            md = MessageDigest.getInstance("MD5");
            byte[] digestData = md.digest(data);
            return toHex(digestData);
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String toHex(byte input[]) {
        if (input == null) {
            return null;
        }
        StringBuffer output = new StringBuffer(input.length * 2);
        for (int i = 0; i < input.length; i++) {
            int current = input[i] & 0xff;
            if (current < 16) {
                output.append("0");
            }
            output.append(Integer.toString(current, 16));
        }
        return output.toString();
    }

    public static String genUrlParams(Map<String, Object> paraMap) {
        if (paraMap == null || paraMap.isEmpty()) {
            return "";
        }
        StringBuffer urlParam = new StringBuffer();
        Set<String> keySet = paraMap.keySet();
        int i = 0;
        for (String key : keySet) {
            urlParam.append(key).append("=")
                    .append(paraMap.get(key) == null ? "" : doEncode(paraMap.get(key).toString()));
            if (++i == keySet.size()) {
                break;
            }
            urlParam.append("&");
        }
        return urlParam.toString();
    }

    static String doEncode(String str) {
        if (str.contains("+")) {
            try {
                return URLEncoder.encode(str, encodingCharset);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return str;
            }
        }
        return str;
    }
}